C.S.Burner 🪙 ━►🔥GIT Node
Node / reticulum_mirror / MeshChatX / files / meshchatx / src / frontend / components / filesync / FilesyncDirectoryBrowserModal.vue
Displaying Raw • Download
meshchatx/src/frontend/components/filesync/FilesyncDirectoryBrowserModal.vue 65ca9ddc823fcc2c8f8653c553b944b85db0875f (65ca9ddc) Text, 8.40 KB
T8b949e<!-- SPDX-License-Identifier: 0BSD -->
Tff7b72<templateTff7b72>
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffopenTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6fffixed inset-0 z-[60] flex items-center justify-center bg-black/50 p-4Ta5d6ff"
@click.Te6edf3self=Ta5d6ff"Te6edf3$emitTa5d6ff(Ta5d6ff'Ta5d6ffcloseTa5d6ff'Ta5d6ff)Ta5d6ff"
Tff7b72>
Tff7b72<div
Te6edf3class=Ta5d6ff"Ta5d6ffflex w-full max-w-lg max-h-[min(36rem,90vh)] flex-col rounded-2xl border border-sem-border-card bg-sem-surface shadow-xlTa5d6ff"
Te6edf3role=Ta5d6ff"Ta5d6ffdialogTa5d6ff"
Te6edf3:aria-label=Ta5d6ff"Te6edf3$tTa5d6ff(Ta5d6ff'Ta5d6ffrns_filesync.browser_titleTa5d6ff'Ta5d6ff)Ta5d6ff"
Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex items-center justify-between gap-2 border-b border-sem-border px-5 py-4Ta5d6ff"Tff7b72>
Tff7b72<h2 Te6edf3class=Ta5d6ff"Ta5d6fftext-lg font-semibold text-sem-fgTa5d6ff"Tff7b72>{{ Te6edf3$t("rns_filesync.browser_title") }}Tff7b72</h2>
Tff7b72<button
Te6edf3type=Ta5d6ff"Ta5d6ffbuttonTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffrounded-lg p-1 text-sem-fg-muted hover:bg-sem-surface-mutedTa5d6ff"
Te6edf3:title=Ta5d6ff"Te6edf3$tTa5d6ff(Ta5d6ff'Ta5d6ffcommon.closeTa5d6ff'Ta5d6ff)Ta5d6ff"
@Te6edf3click=Ta5d6ff"Te6edf3$emitTa5d6ff(Ta5d6ff'Ta5d6ffcloseTa5d6ff'Ta5d6ff)Ta5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6ffcloseTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsize-5Ta5d6ff" Tff7b72/>
Tff7b72</button>
Tff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffpx-5 pt-3 space-y-2Ta5d6ff"Tff7b72>
Tff7b72<p Te6edf3class=Ta5d6ff"Ta5d6fftext-xs text-sem-fg-mutedTa5d6ff"Tff7b72>{{ Te6edf3$t("rns_filesync.browser_hint") }}Tff7b72</p>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex items-center gap-2Ta5d6ff"Tff7b72>
Tff7b72<button
Te6edf3type=Ta5d6ff"Ta5d6ffbuttonTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffsecondary-chip px-2.5 py-1.5 text-xs shrink-0Ta5d6ff"
Te6edf3:disabled=Ta5d6ff"Ta5d6ffbusy || !parentTa5d6ff"
Te6edf3:title=Ta5d6ff"Te6edf3$tTa5d6ff(Ta5d6ff'Ta5d6ffrns_filesync.browser_upTa5d6ff'Ta5d6ff)Ta5d6ff"
@Te6edf3click=Ta5d6ff"Ta5d6ffgoParentTa5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6ffarrow-upTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffw-4 h-4Ta5d6ff" Tff7b72/>
{{ Te6edf3$t("rns_filesync.browser_up") }}
Tff7b72</button>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffinput-field flex-1 min-w-0 !py-2 font-mono text-xs truncateTa5d6ff" Te6edf3:title=Ta5d6ff"Ta5d6ffcurrentTa5d6ff"Tff7b72>
{{ current || "..." }}
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex-1 overflow-y-auto custom-scrollbar px-5 py-3Ta5d6ff"Tff7b72>
Tff7b72<div Te6edf3v-if=Ta5d6ff"Ta5d6ffbusy && directories.length === 0Ta5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffpy-8 text-center text-sm text-sem-fg-mutedTa5d6ff"Tff7b72>
{{ Te6edf3$t("rns_filesync.browser_loading") }}
Tff7b72</div>
Tff7b72<div Te6edf3v-else-if=Ta5d6ff"Ta5d6ffdirectories.length === 0Ta5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffpy-8 text-center text-sm text-sem-fg-mutedTa5d6ff"Tff7b72>
{{ Te6edf3$t("rns_filesync.browser_empty") }}
Tff7b72</div>
Tff7b72<ul v-else Te6edf3class=Ta5d6ff"Ta5d6ffspace-y-1Ta5d6ff"Tff7b72>
Tff7b72<li Te6edf3v-for=Ta5d6ff"Ta5d6ffentry in directoriesTa5d6ff" Te6edf3:key=Ta5d6ff"Ta5d6ffentry.pathTa5d6ff"Tff7b72>
Tff7b72<button
Te6edf3type=Ta5d6ff"Ta5d6ffbuttonTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffflex w-full items-center gap-2 rounded-lg border border-sem-border px-3 py-2 text-left text-sm transition-colors hover:bg-sem-surface-mutedTa5d6ff"
@Te6edf3click=Ta5d6ff"Ta5d6ffenterDirectory(entry.path)Ta5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon
Te6edf3icon-name=Ta5d6ff"Ta5d6fffolderTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffw-5 h-5 shrink-0 text-emerald-600 dark:text-emerald-400Ta5d6ff"
Tff7b72/>
Tff7b72<span Te6edf3class=Ta5d6ff"Ta5d6ffmin-w-0 truncateTa5d6ff"Tff7b72>{{ entry.name }}Tff7b72</span>
Tff7b72</button>
Tff7b72</li>
Tff7b72</ul>
Tff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffborder-t border-sem-border px-5 py-3 space-y-3Ta5d6ff"Tff7b72>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex flex-col sm:flex-row gap-2Ta5d6ff"Tff7b72>
Tff7b72<input
Te6edf3v-model=Ta5d6ff"Ta5d6ffnewFolderNameTa5d6ff"
Te6edf3type=Ta5d6ff"Ta5d6fftextTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffinput-field flex-1 min-w-0 !py-2 text-smTa5d6ff"
Te6edf3:placeholder=Ta5d6ff"Te6edf3$tTa5d6ff(Ta5d6ff'Ta5d6ffrns_filesync.browser_new_placeholderTa5d6ff'Ta5d6ff)Ta5d6ff"
Te6edf3:disabled=Ta5d6ff"Ta5d6ffbusyTa5d6ff"
@keydown.enter.Te6edf3prevent=Ta5d6ff"Ta5d6ffcreateFolderTa5d6ff"
Tff7b72/>
Tff7b72<button
Te6edf3type=Ta5d6ff"Ta5d6ffbuttonTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffsecondary-chip px-3 py-2 text-xs shrink-0Ta5d6ff"
Te6edf3:disabled=Ta5d6ff"Ta5d6ffbusy || !newFolderName.trim()Ta5d6ff"
@Te6edf3click=Ta5d6ff"Ta5d6ffcreateFolderTa5d6ff"
Tff7b72>
Tff7b72<MaterialDesignIcon Te6edf3icon-name=Ta5d6ff"Ta5d6fffolder-plus-outlineTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffw-4 h-4Ta5d6ff" Tff7b72/>
{{ Te6edf3$t("rns_filesync.browser_new") }}
Tff7b72</button>
Tff7b72</div>
Tff7b72<div Te6edf3class=Ta5d6ff"Ta5d6ffflex justify-end gap-2Ta5d6ff"Tff7b72>
Tff7b72<button Te6edf3type=Ta5d6ff"Ta5d6ffbuttonTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6ffsecondary-chip px-4 py-2 text-smTa5d6ff" @Te6edf3click=Ta5d6ff"Te6edf3$emitTa5d6ff(Ta5d6ff'Ta5d6ffcloseTa5d6ff'Ta5d6ff)Ta5d6ff"Tff7b72>
{{ Te6edf3$t("common.cancel") }}
Tff7b72</button>
Tff7b72<button
Te6edf3type=Ta5d6ff"Ta5d6ffbuttonTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffprimary-chip px-4 py-2 text-smTa5d6ff"
Te6edf3:disabled=Ta5d6ff"Ta5d6ffbusy || !currentTa5d6ff"
@Te6edf3click=Ta5d6ff"Ta5d6ffconfirmSelectionTa5d6ff"
Tff7b72>
{{ Te6edf3$t("rns_filesync.browser_select") }}
Tff7b72</button>
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</div>
Tff7b72</template>
Tff7b72<scriptTff7b72>
import MaterialDesignIcon from "../MaterialDesignIcon.vue";
import ToastUtils from "../../js/ToastUtils";
export default {
name: "FilesyncDirectoryBrowserModal",
components: {
MaterialDesignIcon,
},
props: {
open: {
type: Boolean,
default: false,
},
initialPath: {
type: String,
default: "",
},
},
emits: ["close", "select"],
data() {
return {
busy: false,
root: "",
current: "",
parent: null,
directories: [],
newFolderName: "",
};
},
watch: {
open: {
immediate: true,
async handler(isOpen) {
if (!isOpen) {
return;
}
this.newFolderName = "";
const start = String(this.initialPath || "").trim();
const loaded = await this.load(start || undefined);
if (!loaded && start) {
await this.load(undefined);
}
},
},
},
methods: {
async load(path) {
this.busy = true;
try {
const url = path
? `/api/v1/filesync/directories?path=${encodeURIComponent(path)}`
: "/api/v1/filesync/directories";
const response = await window.api.get(url);
const data = response?.data || {};
this.root = data.root || "";
this.current = data.current || "";
this.parent = data.parent || null;
this.directories = Array.isArray(data.directories) ? data.directories : [];
return true;
} catch (err) {
ToastUtils.error(err?.message || this.$t("rns_filesync.error"));
return false;
} finally {
this.busy = false;
}
},
async enterDirectory(path) {
await this.load(path);
},
async goParent() {
if (!this.parent) {
return;
}
await this.load(this.parent);
},
async createFolder() {
const name = String(this.newFolderName || "").trim();
if (!name) {
return;
}
this.busy = true;
try {
const response = await window.api.post("/api/v1/filesync/directories", {
parent: this.current,
name,
});
const created = response?.data?.path;
this.newFolderName = "";
ToastUtils.success(this.$t("rns_filesync.browser_created"));
if (created) {
await this.load(created);
} else {
await this.load(this.current);
}
} catch (err) {
ToastUtils.error(err?.message || this.$t("rns_filesync.error"));
} finally {
this.busy = false;
}
},
confirmSelection() {
const path = String(this.current || "").trim();
if (!path) {
return;
}
this.$emit("select", path);
this.$emit("close");
},
},
};
Tff7b72</script>
Served by rngit 1.5.2 - Generated in 0.02s